#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QStack>
#include<QPushButton>
#include<QMessageBox>
#include<map>
#include<cmath>
#include<QClipboard>
#include<QApplication>
#include<QDebug>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->lineEdit->setAlignment(Qt::AlignRight);
    ui->lineEdit->setText("0");
   //参数初始化
    operatorFlag = false;
    waittingForOperand=false;
    frontzero=true;
    pointflag=false;
    brkflag=0;
    fxflag=false;
    //按键的绑定
        connect(ui->btn0, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn1, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn2, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn3, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn4, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn5, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn6, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn7, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn8, SIGNAL(clicked()), this, SLOT(btnnumClicked()));
        connect(ui->btn9, SIGNAL(clicked()), this, SLOT(btnnumClicked()));

        //符号（加减乘除和括号 以及^
        connect(ui->btnadd, SIGNAL(clicked()), this, SLOT(btnoprClicked()));
        connect(ui->btndiv, SIGNAL(clicked()), this, SLOT(btnoprClicked()));
        connect(ui->btnminus, SIGNAL(clicked()), this, SLOT(btnoprClicked()));
        connect(ui->btnmul, SIGNAL(clicked()), this, SLOT(btnoprClicked()));
        connect(ui->btnplus, SIGNAL(clicked()), this, SLOT(btnoprClicked()));
      //等号
        connect(ui->btnequ, SIGNAL(clicked()), this, SLOT(btnequClicked()));
     //小数点
        connect(ui->btnpoint,SIGNAL(clicked()), this, SLOT(btnpointClicked()));
      //括号
        connect(ui->btnbrk_left,SIGNAL(clicked()), this, SLOT(btnbrkClicked()));
        connect(ui->btnbrk_right,SIGNAL(clicked()), this, SLOT(btnbrkClicked()));

      //函数(单目
     connect(ui->btnsin,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btncos,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btntan,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btnexp,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btnsqrt,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btnln,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
     connect(ui->btnlg,SIGNAL(clicked()), this, SLOT(btnfxClicked()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::btnnumClicked()//数字键显示和储存
{
    QPushButton *buttonClicked = qobject_cast<QPushButton *>(sender());
   int  buttonValue = buttonClicked->text().toInt();
//    if(waittingForOperand)
//    {
//        ui->lineEdit->clear();
//        waittingForOperand = false;
//   }
     QString temp=ui->lineEdit->text();
    if(frontzero)
    {
          if(temp.right(1)=='0')temp.remove(temp.length()-1,1);
          if(buttonValue){
          frontzero = false;
          }
     }
    ui->lineEdit->setText(temp+QString::number(buttonValue));
    operatorFlag=false;
}
void MainWindow::btnpointClicked(){
    QString temp=ui->lineEdit->text();
    if(!pointflag&&'0'<=temp.right(1)&&
            temp.right(1)<='9'){
        ui->lineEdit->setText(ui->lineEdit->text()+".");
        pointflag=true;
        frontzero=false;
        return;
    }
}
void MainWindow::btnoprClicked()
{
    QPushButton *buttonClicked = qobject_cast<QPushButton *>(sender());
    if(!operatorFlag){
        QString op=buttonClicked->text();
        ui->lineEdit->setText(ui->lineEdit->text()+op);
        //waittingForOperand=true;
        fxflag=false;
        operatorFlag=true;
        frontzero=true;
        pointflag=false;//加了运算符关于数字的参数都要初始化
    }
    else return;
}
void MainWindow::btnfxClicked(){
    if(!fxflag){
 QPushButton *buttonClicked = qobject_cast<QPushButton *>(sender());
 QString tfx=buttonClicked->text();
 QString tle=ui->lineEdit->text();
 if(tle=='0'){ui->lineEdit->setText(tfx+"("+'0');
     brkflag++;
     //operatorFlag=true;
     frontzero=true;
     pointflag=false;
     fxflag=true;
     return;}
 if(('0'<=tle.right(1)&&'9'>=tle.right(1))||tle.right(1)=='.')return;

 ui->lineEdit->setText(tle+tfx+"("+'0');
  brkflag++;
 //waittingForOperand=true;
 //operatorFlag=true;
 frontzero=true;
 pointflag=false;
 fxflag=true;
 return;
    }
    else  return;
}

void MainWindow::btnbrkClicked(){
    QPushButton *buttonClicked = qobject_cast<QPushButton *>(sender());
    //左括号
    if(buttonClicked->text()=='('){
        QString temp=ui->lineEdit->text();
        if( temp.right(1)!='.'&&temp.right(1)!=')'&&
           (temp.right(1)>'9' ||temp.right(1)<'0'))
    {
            ui->lineEdit->setText(temp+"(");
            brkflag++;
            frontzero=false;
            fxflag=false;
    }
        else if(temp=="0"){ui->lineEdit->setText("(");brkflag++;}
    }
    //右括号
    if(buttonClicked->text()==")"){
       if(brkflag<=0)return;
else{
    QString temp_=ui->lineEdit->text();
  if(temp_.right(1)>='0'&&temp_.right(1)<='9'||temp_.right(1)==")")
 {
   ui->lineEdit->setText(temp_+")");
      brkflag--;

}
        }
    }
}


void MainWindow::on_btndel_clicked()
{

    QString text = ui->lineEdit->text();
   operatorFlag=false;
   if(text.right(1)=='.'){pointflag=false;frontzero=true;}
        text.chop(1);  
        if(text.isEmpty())
        {
            text = "0";
            frontzero= true;
        }
        ui->lineEdit->setText(text);
        QString tar=text.right(1);
        if(tar<"0"||tar>"9")pointflag=operatorFlag=true;
}



void MainWindow::btnequClicked(){
    if(brkflag){
        QMessageBox::information(this, tr("ERROR!"),
       tr("括号不匹配！"));
        return;
    }
        QString s2 = ui->lineEdit->text();

        if((s2.right(1)<'0'||s2.right(1)>'9')&&s2.right(1)!=')'){
            QMessageBox::information(this, tr("ERROR!"),
           tr("缺少运算分量！"));
           return;
        }


         QString result=calculate(s2);
       ui->lineEdit->setText(result);
       //等于号之后的状态等于输入了一个数字
       //（但没输入运算符 的状态，关于运算符的参数要重置
       operatorFlag=false;
       if(result=='0')frontzero=true;
       else frontzero=false;
}

void MainWindow::on_btnAC_clicked()
{
    ui->lineEdit->setText("0");
    operatorFlag = false;
    waittingForOperand=false;
    frontzero=true;
    pointflag=false;
    brkflag=0;
    fxflag=false;
}



/* 中缀转后缀 src带入中缀式，des带出后缀式 */
void MainWindow::InfixToSuffix(char* src, char* des)
{
    std::map<char, int> priority;
    priority['+'] = 0;
    priority['-'] = 0;
    priority['*'] = 1;
    priority['/'] = 1;
    priority['^'] = 2;
    priority['s'] = 3;
    priority['c'] = 3;
    priority['t'] = 3;
    priority['n'] = 3;//ln
    priority['g'] = 3; //lg
    priority['e'] = 3;//exp
    priority['q'] = 3; //sqrt

    des[0]='0';
    des[1]=' ';
    int k = 2;
    /* 符号栈 */
    QStack<char> symbol;

    int i = 0;

    while (src[i] != '\0')
    {

        if (src[i] == ' ')		//如果当前字符是空格，则往后走一个
        {
            i++;
            continue;
        }
        else if (src[i] >= '0' && src[i] <= '9' || src[i] == '.')
        {
            des[k++] = src[i];
            if ((src[i + 1] < '0' || src[i + 1]>'9') && src[i + 1] != '.')		//数字后加空格
            {
                des[k++] = ' ';
            }
        }
        else if (src[i] == '(')	//左括号直接入栈
        {
            symbol.push(src[i]);
        }
        else if (src[i] == ')')	//遇到 ） ，输出（ ）之间的所有符号
        {
            while (symbol.top() != '(')
            {
                des[k++] = symbol.top();
                des[k++] = ' ';
                symbol.pop();
            }
            symbol.pop();
        }

        /*----------------- 运算符 -------------------------------*/
        else
        {
            switch (src[i])
            {
            case '+':
            case '-':
            case '*':
            case '/':
            case '^':
                if (symbol.empty())		//如果符号栈为空，直接入符号
                {
                    symbol.push(src[i]);
                }
                else				//否则，判断是否选择入符号栈还是出栈顶元素
                {
                    char tempTop = symbol.top();
                    if (tempTop != '(' && priority[src[i]] <= priority[tempTop])	//出符号栈
                    {
                        des[k++] = symbol.top();
                        des[k++] = ' ';
                        symbol.pop();
                        continue;//这是作用于外部循环的continue，这样i就不会加，当前的数跳到else的push操作，再i++
                    }
                    else			//当前符号优先级高，入符号栈
                    {
                        symbol.push(src[i]);
                    }
                }
                break;
            case's'://  sin&sqrt
                if (symbol.empty())		//如果符号栈为空，直接入符号
                {
                    if(src[i+1]=='i')
                    symbol.push(src[i]);
                else
                    symbol.push(src[i+1]);
                }
                else				//否则，判断是否选择入符号栈还是出栈顶元素
                {
                    char tempTop = symbol.top();
                    if(src[i+1]=='i'){
                    if (tempTop != '(' && priority[src[i]] <= priority[tempTop])	//出符号栈
                    {
                        des[k++] = symbol.top();
                        des[k++] = ' ';
                        symbol.pop();
                        continue;
                    }
                    else			//当前符号优先级高，入符号栈
                    {
                        symbol.push(src[i]);
                    }
                    }
                    else {
                        if (tempTop != '(' && priority[src[i+1]] <= priority[tempTop])	//出符号栈
                        {
                            des[k++] = symbol.top();
                            des[k++] = ' ';
                            symbol.pop();
                            continue;
                        }
                        else			//当前符号优先级高，入符号栈
                        {
                            symbol.push(src[i+1]);
                        }
                    }
                }
                if (src[i + 1] == 'i')i += 2;
                else i += 3;
                break;
            case'c':
            case't':
            case'e':
                if (symbol.empty())		//如果符号栈为空，直接入符号
                {
                    symbol.push(src[i]);
                }
                else				//否则，判断是否选择入符号栈还是出栈顶元素
                {
                    char tempTop = symbol.top();
                    if (tempTop != '(' && priority[src[i]] <= priority[tempTop])	//出符号栈
                    {
                        des[k++] = symbol.top();
                        des[k++] = ' ';
                        symbol.pop();
                        continue;
                    }
                    else			//当前符号优先级高，入符号栈
                    {
                        symbol.push(src[i]);
                    }
                }
                i+=2;
                break;
            case'l':
                if (symbol.empty())		//如果符号栈为空，直接入符号
                {
                    symbol.push(src[i+1]);
                }
                else				//否则，判断是否选择入符号栈还是出栈顶元素
                {
                    char tempTop = symbol.top();
                    if (tempTop != '(' && priority[src[i+1]] <= priority[tempTop])	//出符号栈
                    {
                        des[k++] = symbol.top();
                        des[k++] = ' ';
                        symbol.pop();
                        continue;
                    }
                    else			//当前符号优先级高，入符号栈
                    {
                        symbol.push(src[i+1]);
                    }
                }
                i += 1;
                break;

            default:
                i++;
                break;
            }

        }
        i++;
            /* 遍历下一字符 */
    }
    /*字符串已遍历完，把符号栈中剩余的符号入栈到数字栈中 */
    while (!symbol.empty())
    {
        des[k++] = symbol.top();
        des[k++] = ' ';
        symbol.pop();
    }
    des[k] = '\0';
}

QString MainWindow:: calculate(QString s2) {
    QByteArray ba2;
    ba2.append(s2);     //也可以 ba2 = s2.toLatin1();
    char *src = ba2.data();
    char* des = new char[(strlen(src)+1)*3+3];
    InfixToSuffix(src, des);
    QStack<double>num;
    int i = 0;
    while (des[i] != '\0') {
        while (des[i] >= '0' && des[i] <= '9' || des[i] == ' ' || des[i] == '.') {
            if (des[i] != ' ')
            {
                QStack<double>temp;
                double tempnum = 0;
                int n = 1;
                double m = 0.1;
                while (des[i] != ' ' && des[i] != '.') {
                    temp.push((des[i] - '0'));
                    i++;
                }
                if (des[i] == '.') {
                    while (des[++i] != ' ') {
                        double dt = des[i] - '0';
                        tempnum += dt * m;
                        m /= 10;
                    }
                }
                while (!temp.empty()) {
                    tempnum += temp.top() * n;
                    n *= 10;
                    temp.pop();
                }

                num.push(tempnum);
            }
            else i++;
        }
        while (des[i] < '0' || des[i]> '9' || des[i] == ' ')
        {
            double temp1 = 0, temp2 = 0, temp3 = 0;
            switch (des[i++]) {
            case'+':temp1 = num.top();
                num.pop();
                temp2 = num.top();
                num.pop();
                temp3 = temp1 + temp2;
                num.push(temp3);
                break;
            case'-': temp1 = num.top();
                num.pop();
                temp2 = num.top();
                num.pop();
                temp3 = temp2 - temp1;
                num.push(temp3);
                break;
            case'*':temp1 = num.top();
                num.pop();
                temp2 = num.top();
                num.pop();
                temp3 = temp2 * temp1;
                num.push(temp3);
                break;
            case'/': temp1 = num.top();
                num.pop();
                temp2 = num.top();
                num.pop();
                temp3 = temp2 / temp1;
                num.push(temp3);
                break;
            case'^':temp1 = num.top();
                num.pop();
                temp2 = num.top();
                num.pop();
                temp3 =std::pow(temp2,temp1);
                num.push(temp3);
                break;
            case's':temp3 = num.top();
                num.pop();
                temp3 = std::sin(temp3 / 180.0 * M_PI);
                num.push(temp3);
                break;
            case'c':temp3 = num.top();
                num.pop();
                temp3 =std::cos(temp3 / 180.0 * M_PI);
                num.push(temp3);
                break;
            case't':temp3 = num.top();
                num.pop();
                temp3 =std::tan(temp3 / 180.0 * M_PI);
                num.push(temp3);
                 break;
            case'g':temp3 = num.top();
                if(temp3<=0){
                    QMessageBox::information(this, tr("ERROR!"),
                     tr("对数计算分量不能<=0！"));
                return s2;
                }
                num.pop();
                temp3 =std::log10(temp3);
                num.push(temp3);
                break;
            case'n':temp3 = num.top();
                if(temp3<=0){
                    QMessageBox::information(this, tr("ERROR!"),
                     tr("对数计算分量不能<=0！"));
                return s2;
                }
                num.pop();
                temp3 =std::log(temp3);
                num.push(temp3);
                break;
            case'e':temp3 = num.top();
                num.pop();
                temp3 =std::exp(temp3);
                num.push(temp3);
                break;
            case'q':
                temp3 = num.top();
                num.pop();
                temp3 =std::sqrt(temp3);
                num.push(temp3);
                break;
            default:break;
            }
            if (des[i] == '\0')break;
        }
    }
    return QString::number(num.top());
}
